package com.wg.net.server.http;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * CORS（跨域资源共享）配置类，用于生成CORS响应头
 *
 * @author 少爷123
 */
public class CorsConfig {
    private static final Log log = LogFactory.get(CorsConfig.class);

    /**
     * 默认允许的源（所有源）
     */
    private static final String DEFAULT_ALLOWED_ORIGINS = "*";
    /**
     * 默认允许的方法（GET, POST, OPTIONS）
     */
    private static final String DEFAULT_ALLOWED_METHODS = "GET, POST, OPTIONS";
    /**
     * 默认允许的请求头（Content-Type, Authorization）
     */
    private static final String DEFAULT_ALLOWED_HEADERS = "Content-Type, Authorization";
    /**
     * 默认预检缓存时间（3600秒）
     */
    private static final int DEFAULT_MAX_AGE = 3600;
    /**
     * 默认是否允许凭证（false）
     */
    private static final boolean DEFAULT_ALLOW_CREDENTIALS = false;

    /**
     * 允许的源（支持通配符*或多个具体源，如"http://a.com,https://b.com"）
     */
    private final List<String> allowedOrigins = new CopyOnWriteArrayList<>();
    /**
     * 允许的HTTP方法（如"GET, POST, PUT, DELETE"）
     */
    private final List<String> allowedMethods = new CopyOnWriteArrayList<>();
    /**
     * 允许的请求头（如"Content-Type, X-Custom-Header"）
     */
    private final List<String> allowedHeaders = new CopyOnWriteArrayList<>();
    /**
     * 是否允许客户端发送Cookie等凭证
     */
    private boolean allowCredentials;
    /**
     * 预检请求（OPTIONS）的缓存时间（秒），0表示不缓存
     */
    private int maxAge;

    /**
     * 默认构造函数（使用默认配置）
     */
    public CorsConfig() {
        this(DEFAULT_ALLOWED_ORIGINS,
                DEFAULT_ALLOWED_METHODS,
                DEFAULT_ALLOWED_HEADERS,
                DEFAULT_ALLOW_CREDENTIALS,
                DEFAULT_MAX_AGE);
    }

    /**
     * 自定义配置构造函数
     *
     * @param allowedOrigins   允许的源（逗号分隔，或"*"）
     * @param allowedMethods   允许的方法（逗号分隔）
     * @param allowedHeaders   允许的请求头（逗号分隔）
     * @param allowCredentials 是否允许凭证
     * @param maxAge           预检缓存时间（秒）
     */
    public CorsConfig(String allowedOrigins, String allowedMethods, String allowedHeaders,
                      boolean allowCredentials, int maxAge) {
        setAllowedOrigins(allowedOrigins);
        setAllowedMethods(allowedMethods);
        setAllowedHeaders(allowedHeaders);
        this.allowCredentials = allowCredentials;
        this.maxAge = maxAge;
        validateConfig(); // 初始化时校验配置
    }

    /**
     * 生成Access-Control-Allow-Origin头值
     *
     * @return 头值字符串（如"*"或"http://a.com,https://b.com"）
     */
    public String getAccessControlAllowOrigin() {
        if (allowCredentials && allowedOrigins.contains("*")) {
            log.warn("当allowCredentials为true时，Access-Control-Allow-Origin不能为*，已自动过滤");
            return StrUtil.join(",", allowedOrigins.stream()
                    .filter(origin -> !"*".equals(origin))
                    .toArray(Object[]::new));
        }
        return StrUtil.join(",", allowedOrigins);
    }

    /**
     * 生成Access-Control-Allow-Methods头值
     *
     * @return 头值字符串（如"GET, POST, PUT"）
     */
    public String getAccessControlAllowMethods() {
        return StrUtil.join(",", allowedMethods);
    }

    /**
     * 生成Access-Control-Allow-Headers头值
     *
     * @return 头值字符串（如"Content-Type, Authorization"）
     */
    public String getAccessControlAllowHeaders() {
        return StrUtil.join(",", allowedHeaders);
    }

    /**
     * 生成Access-Control-Allow-Credentials头值
     *
     * @return "true"或"false"
     */
    public String getAccessControlAllowCredentials() {
        return String.valueOf(allowCredentials);
    }

    /**
     * 生成Access-Control-Max-Age头值
     *
     * @return 秒数字符串（如"3600"）或空字符串（maxAge=0时）
     */
    public String getAccessControlMaxAge() {
        return maxAge > 0 ? String.valueOf(maxAge) : "";
    }

    // ------------------------------ 配置管理 ------------------------------

    /**
     * 添加允许的源（支持通配符*）
     *
     * @param origin 源地址（如"http://example.com"或"*"）
     */
    public void addAllowedOrigin(String origin) {
        if (StrUtil.isNotBlank(origin)) {
            allowedOrigins.add(origin);
            validateConfig();
        }
    }

    /**
     * 批量设置允许的源（覆盖原有配置）
     *
     * @param origins 源地址列表（逗号分隔或直接传入List）
     */
    public void setAllowedOrigins(String origins) {
        setAllowedOrigins(StrUtil.split(origins, ","));
    }

    public void setAllowedOrigins(List<String> origins) {
        allowedOrigins.clear();
        if (origins != null) {
            allowedOrigins.addAll(origins);
        }
        validateConfig();
    }

    /**
     * 添加允许的HTTP方法
     *
     * @param method 方法名（如"GET"、"POST"）
     */
    public void addAllowedMethod(String method) {
        if (StrUtil.isNotBlank(method)) {
            allowedMethods.add(method.toUpperCase());
            validateConfig();
        }
    }

    /**
     * 批量设置允许的HTTP方法（覆盖原有配置）
     *
     * @param methods 方法列表（逗号分隔或直接传入List）
     */
    public void setAllowedMethods(String methods) {
        setAllowedMethods(StrUtil.split(methods, ","));
    }

    public void setAllowedMethods(List<String> methods) {
        allowedMethods.clear();
        if (methods != null) {
            methods.forEach(m -> allowedMethods.add(m.toUpperCase()));
        }
        validateConfig();
    }

    /**
     * 添加允许的请求头
     *
     * @param header 请求头名（如"Content-Type"）
     */
    public void addAllowedHeader(String header) {
        if (StrUtil.isNotBlank(header)) {
            allowedHeaders.add(header);
            validateConfig();
        }
    }

    /**
     * 批量设置允许的请求头（覆盖原有配置）
     *
     * @param headers 请求头列表（逗号分隔或直接传入List）
     */
    public void setAllowedHeaders(String headers) {
        setAllowedHeaders(StrUtil.split(headers, ","));
    }

    public void setAllowedHeaders(List<String> headers) {
        allowedHeaders.clear();
        if (headers != null) {
            allowedHeaders.addAll(headers);
        }
        validateConfig();
    }

    /**
     * 校验配置有效性（如allowCredentials为true时，allowedOrigins不能包含*）
     */
    public void validateConfig() {
        if (allowCredentials && allowedOrigins.contains("*")) {
            log.error("CORS配置冲突：当allowCredentials为true时，Access-Control-Allow-Origin不能为*");
            throw new IllegalStateException("Invalid CORS configuration: allowCredentials=true with allowedOrigins=*");
        }
    }

    public List<String> getAllowedOrigins() {
        return new ArrayList<>(allowedOrigins);
    }

    public List<String> getAllowedMethods() {
        return new ArrayList<>(allowedMethods);
    }

    public List<String> getAllowedHeaders() {
        return new ArrayList<>(allowedHeaders);
    }

    public boolean isAllowCredentials() {
        return allowCredentials;
    }

    public void setAllowCredentials(boolean allowCredentials) {
        this.allowCredentials = allowCredentials;
        validateConfig();
    }

    public int getMaxAge() {
        return maxAge;
    }

    public void setMaxAge(int maxAge) {
        this.maxAge = Math.max(maxAge, 0); // 不允许负数
    }

    /**
     * 创建允许所有源的CORS配置（开发环境常用）
     *
     * @return CorsConfig实例
     */
    public static CorsConfig allowAll() {
        return new CorsConfig("*", DEFAULT_ALLOWED_METHODS, DEFAULT_ALLOWED_HEADERS, false, DEFAULT_MAX_AGE);
    }

    /**
     * 创建严格模式的CORS配置（生产环境推荐）
     *
     * @param allowedOrigins 允许的源列表（如["http://a.com", "https://b.com"]）
     * @param allowedMethods 允许的方法列表（如["GET", "POST"]）
     * @return CorsConfig实例
     */
    public static CorsConfig strict(List<String> allowedOrigins, List<String> allowedMethods) {
        CorsConfig config = new CorsConfig();
        config.setAllowedOrigins(allowedOrigins);
        config.setAllowedMethods(allowedMethods);
        config.setAllowedHeaders(DEFAULT_ALLOWED_HEADERS);
        config.setAllowCredentials(false);
        config.setMaxAge(DEFAULT_MAX_AGE);
        return config;
    }
}
